package com.think.utils;

import it.sauronsoftware.ftp4j.FTPClient;
import it.sauronsoftware.ftp4j.FTPDataTransferListener;
import it.sauronsoftware.ftp4j.FTPException;
import it.sauronsoftware.ftp4j.FTPFile;
import it.sauronsoftware.ftp4j.FTPIllegalReplyException;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @description	<pre>
 * 基于ftp4j的线程安全的FTP连接工具类,
 * 依赖于ftp4j，slf4j
 *	</pre>
 * @author	dzy
 * @date	2016年7月4日
 */
public class FtpToolkit {
	protected Logger logger = LoggerFactory.getLogger(FtpToolkit.class);
	private static FtpToolkit self;
	private ThreadLocal<FTPClient> ftpClientThreadLocal = new ThreadLocal<FTPClient>();
	private FtpToolkit(){}
	private String host;
	private int port;
	private String username;
	private String password;
	public static FtpToolkit getInstance(){
		if(self == null){
			 self = new FtpToolkit();
		}
		return self;
	}
	
	public FtpToolkit setConfig(String host,int port,String user,String pwd){
		self.host=host;
		self.port=port;
		self.username=user;
		self.password=pwd;
		return self;
	}
	
	private FTPClient getFTPClient() throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException{
		if (ftpClientThreadLocal.get() != null && ftpClientThreadLocal.get().isConnected()) {
			return ftpClientThreadLocal.get();
		} else {
			FTPClient ftpClient = new FTPClient(); //构建一个FtpClient实例
			ftpClient.setType(FTPClient.TYPE_BINARY);//二进制
			ftpClient.setCharset("GBK");//设置编码
			ftpClient.setPassive(true);//被动模式
			ftpClient.setAutoNoopTimeout(36000);//超时
			ftpClient.connect(host, port);
			ftpClient.login(username, password);
			if(logger.isDebugEnabled()){
				logger.debug(username+ "is login...");
			}
			ftpClientThreadLocal.set(ftpClient);
			return ftpClient;
		}
	}
	
	/**
	 * 上传
	 * @param remoteDir 远程文件目录
	 * @param local		本地文件路径
	 * @return
	 */
	public boolean upload(String remoteDir, String local){
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			client.changeDirectory(remoteDir);
			MyTransferListener listener = new MyTransferListener();
			client.upload(new File(local),listener);
			return listener.getResult();
		}catch(Exception e) {
			logger.error("ftp upload fail,because:"+e.getMessage(),e);
			return false;
		}
	}
	
	/**
	 * 上传
	 * @param remotePath 远程文件路径
	 * @param in
	 * @return
	 */
	public boolean upload(String remotePath, InputStream in){
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(remotePath == null || remotePath.length() == 0){
				logger.info("ftp upload fail,because: remotePath is null");
				return false;
			}
			String remoteDir = remotePath.substring(0,remotePath.lastIndexOf("/"));
			client.changeDirectory(remoteDir);
			MyTransferListener listener = new MyTransferListener();
			client.upload(remotePath, in, 0l, 0l, listener);
			return listener.getResult();
		}catch(Exception e) {
			logger.error("ftp upload fail,because:"+e.getMessage(),e);
			return false;
		}
	}

	/**
	 * 下载
	 * @param remote 远程文件路径
	 * @param local  本地文件路径
	 * @return
	 */
	public boolean download(String remote,String local){
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(remote.contains("/")){
				String remoteDir = remote.substring(0,remote.lastIndexOf("/")+1);
				client.changeDirectory(remoteDir);
				remote = remote.substring(remoteDir.length());
			}
			MyTransferListener listener = new MyTransferListener();
			client.download(remote, new File(local),listener);
			return listener.getResult();
		}catch(Exception e) {
			logger.error("ftp download fail,because:"+e.getMessage(),e);
			return false;
		}
	}
	
	/**
	 * 下载
	 * @param remote 远程文件路径
	 * @param local  本地文件路径
	 * @return
	 */
	public boolean download(String remote,OutputStream out){
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(remote.contains("/")){
				String remoteDir = remote.substring(0,remote.lastIndexOf("/")+1);
				client.changeDirectory(remoteDir);
				remote = remote.substring(remoteDir.length());
			}
			MyTransferListener listener = new MyTransferListener();
			client.download(remote, out, 0L, listener);
			return listener.getResult();
		}catch(Exception e) {
			logger.error("ftp download fail,because:"+e.getMessage(),e);
			return false;
		}
	}
	
	/**
	 * 重命名
	 * @param oldname 原始文件路径
	 * @param newname 新文件路径
	 */
	public void rename(String oldname,String newname){
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(oldname.contains("/")){
				String remoteDir = oldname.substring(0,oldname.lastIndexOf("/")+1);
				client.changeDirectory(remoteDir);
				oldname = oldname.substring(remoteDir.length());
			}
			client.rename(oldname, newname);
		}catch(Exception e) {
			logger.error("ftp rename fail,because:"+e.getMessage(),e);
		}
	}
	
	/**
	 * 删除文件
	 * @param remote 远程文件路径
	 */
	public void delete(String remote){
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(remote.endsWith("/") || (remote.lastIndexOf(".")+3) >= remote.length()){
				//是目录
				client.deleteDirectory(remote);
			}else if(remote.contains("/")){//TODO 不确定是否需要切换目录
				String remoteDir = remote.substring(0,remote.lastIndexOf("/")+1);
				client.changeDirectory(remoteDir);
				remote = remote.substring(remoteDir.length());
			}
			client.deleteFile(remote);
		}catch(Exception e) {
			logger.error("ftp delete fail,because:"+e.getMessage(),e);
		}
	}
	
	/**
	 * 获取指定目录下的所有目录和文件，包括. ..
	 * @param remoteDir
	 * @return
	 */
	public String[] getFiles(String remoteDir){
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(remoteDir.contains("/")){
				client.changeDirectory(remoteDir);
			}
			FTPFile[] list = client.list();
			if(list == null || list.length == 1){
				return new String[0];
			}
			return client.listNames();
		}catch(Exception e) {
			logger.error("ftp getFiles fail,because:"+e.getMessage(),e);
			return new String[0];
		}
	}
	
	/**
	 * 获取指定目录下的文件夹，只要目录，并且跳过. ..
	 * @param remoteDir
	 * @return
	 */
	public List<String> getDirs(String remoteDir){
		List<String> resList = new ArrayList<String>();
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(remoteDir.contains("/")){
				client.changeDirectory(remoteDir);
			}
			FTPFile[] list = client.list();
			if(list == null || list.length == 1){
				return resList;
			}
			for (FTPFile ftpFile : list) {
				String name = ftpFile.getName();
				if(ftpFile.getType() == FTPFile.TYPE_DIRECTORY && !(".".equals(name) || "..".equals(name))){
					resList.add(ftpFile.getName());
				}
			}
		}catch(Exception e) {
			logger.error("ftp getFiles fail,because:"+e.getMessage(),e);
		}
		return resList;
	}
	
	/**
	 * 获取指定目录下的文件列表，跳过目录和. ..
	 * @param remoteDir
	 * @return
	 */
	public List<String> getFilenames(String remoteDir){
		List<String> resList = new ArrayList<String>();
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(remoteDir.contains("/")){
				client.changeDirectory(remoteDir);
			}
			FTPFile[] list = client.list();
			if(list == null || list.length == 1){
				return resList;
			}
			for (FTPFile ftpFile : list) {
				if(ftpFile.getType() == FTPFile.TYPE_DIRECTORY || ftpFile.getType() == FTPFile.TYPE_LINK){
					continue;
				}
				resList.add(ftpFile.getName());
			}
		}catch(Exception e) {
			logger.error("ftp getFiles fail,because:"+e.getMessage(),e);
		}
		return resList;
	}
	
	/**
	 * 创建目录，从根目录/开始创建
	 * @param remoteDir
	 */
	public void mkdir(String remoteDir){
		try {
			FTPClient client = getFTPClient();
			client.changeDirectory("/");
			if(remoteDir.contains("/")){
				String[] ss = remoteDir.split("/");
				for (int i = 0; i < ss.length; i++) {
					if(ss[i] == null || ss[i].length() == 0 || ".".endsWith(ss[i])){
						continue;
					}
					if(!exists(ss[i])){
						client.createDirectory(ss[i]);
					}
					client.changeDirectory(ss[i]);
				}
			}else{
				client.createDirectory(remoteDir);
			}
		}catch(Exception e) {
			logger.error("ftp mkdir fail,because:"+e.getMessage(),e);
		}
	}
	
	/**
	 * 判断文件或目录是否存在
	 * @param dir
	 * @return
	 * @throws Exception
	 */
	public boolean exists(String dir) throws Exception {  
        return getFileType(dir) != -1;  
    }  
	
	/** 判断当前为文件还是目录
     * @param dir 
     *            文件或目录
     * @return -1、文件或目录不存在 0、文件 1、目录 
     * @throws Exception 
     */  
    private int getFileType(String dir) throws Exception {  
        FTPFile[] files = null;  
        FTPClient client = getFTPClient();
        try {  
            files = client.list(dir);  
        } catch (Exception e) {  
            return -1;  
        }  
        if (files.length > 1) {  
            return FTPFile.TYPE_DIRECTORY;  
        } else if (files.length == 1) {  
            FTPFile f = files[0];  
            if (f.getType() == FTPFile.TYPE_DIRECTORY) {  
                return FTPFile.TYPE_DIRECTORY;  
            }  
            String path = dir + "/" + f.getName();  
            try {  
                int len = client.list(path).length;  
                if (len == 1) {  
                    return FTPFile.TYPE_DIRECTORY;  
                } else {  
                    return FTPFile.TYPE_FILE;  
                }  
            } catch (Exception e) {  
                return FTPFile.TYPE_FILE;  
            }  
        } else {  
            try {  
                client.changeDirectory(dir);  
                client.changeDirectoryUp();  
                return FTPFile.TYPE_DIRECTORY;  
            } catch (Exception e) {  
                return -1;  
            }  
        }  
    } 
	
    /**
     * 关闭ftp连接线程
     */
	public void disConnect() {
		try {
			FTPClient client = getFTPClient();
			if(client != null && client.isConnected()){
				client.disconnect(true);
			}
		} catch (Exception e) {
			logger.error("ftp close fail,because:"+e.getMessage(),e);
		}
	}
	
	private class MyTransferListener implements FTPDataTransferListener {
		private boolean flag;
		public boolean getResult(){
			return this.flag;
		}
		public void aborted() {}
		public void completed() {
			this.flag = true;
		}
		public void failed() {
			this.flag = false;
		}
		public void started() {}
		public void transferred(int arg0) {}
		
	}
}